Ein Skalar ist, wie Sie seit spätestens gestern wissen, etwas Einzelnes wie eine Zahl oder ein String. Gestern haben Sie schon einiges darüber erfahren, was man mit skalaren Daten und Operatoren machen kann. Heute werde ich Ihnen noch etwas mehr zeigen und das Thema abschließen. Am Ende befassen wir uns mit ein paar verwandten Themen. Heute steht folgendes an:
Gestern hatten wir bereits den grundlegenden Zuweisungsoperator =
kennengelernt,
der einer Variablen einen Wert zuweist. Zuweisungen verwendet man sehr häufig zur
Änderung des Werts einer Variablen basierend auf ihrem aktuellen Wert.
$inc = $inc + 100;
zum Beispiel macht genau, was man erwarten würde: Es nimmt den Wert von $inc
,
addiert 100
dazu und speichert das Ergebnis dann wieder in $inc
. Derartige
Operationen kommen so oft vor, dass es dafür eine Kurzschreibweise, einen eigenen
Operator gibt: Die Variablenbezeichnung kommt auf die linke Seite, in die Mitte der
Operator +=
und auf die rechte Seite der Betrag, um den die Variable geändert
werden soll:
$inc += 100;
Perl hat solche »Schnellzuweisungen« für alle Rechenoperatoren, für die (bis jetzt noch
nicht besprochenen) Stringoperatoren und sogar für &&
und ||
. Tabelle 3.1 zeigt ein
paar dieser Zuweisungsoperatoren. Im Grunde hat so gut wie jeder Operator, der zwei
Operanden hat, eine solche Zuweisungsversion. Dabei gilt allgemein:
Variable Zuweisungsoperator Ausdruck
Variable = Variable Operator Ausdruck
Es gibt nur einen Unterschied zwischen den beiden Formen. In der langen Version wird die Variable zweimal ausgewertet, in der Kurzversion nur einmal. Meistens macht das beim Ergebnis des Ausdrucks keinen Unterschied, aber denken Sie daran, wenn Sie einmal unerwartete Ergebnisse erhalten.
Wie in C kann man mit den Operatoren ++
und --
eine Variable um 1 inkrementieren
bzw. dekrementieren, das heißt, 1 addieren bzw. subtrahieren. Und wie in C können
beide Operatoren entweder als Präfix (vor der Variablen, also ++$x
) oder als Postfix
(nach der Variablen, also $x++
) gesetzt werden. Abhängig davon wird die Variable,
bevor oder nachdem sie verwendet wurde, inkrementiert oder dekrementiert.
»Wie bitte?« denken Sie? Dann erkläre ich es Ihnen genauer: Die Operatoren ++
und
--
verwendet man mit einer Skalarvariablen, um den Wert der Variablen um 1 zu
erhöhen oder zu erniedrigen - sie sind eine Art Abkürzung der +=-
Operatoren oder
der -=-Operatoren. Beide Operatoren können vor der Variablen stehen - das wird
dann Präfixnotation genannt:
++$x
Oder nach der Variablen (Postfixnotation):
$x++
Der Unterschied ist klein, aber fein: Die Position des Operators bestimmt, wann Perl beim Auswerten des Ausdrucks die Variable wirklich inkrementiert. Wenn Sie die Operatoren ganz alleinstehend - nur mit der Variablen, auf der operiert wird - verwenden, gibt es keinen Unterschied zwischen Postfix und Präfix. Die Variable wird inkrementiert, und Perl geht weiter. Wenn diese Operatoren aber auf der rechten Seite einer anderen Variablenzuweisung stehen, können Präfix- und Postfixnotation zu verschiedenen Ergebnissen führen. Schauen wir zum Beispiel auf das folgende Schnipsel Perl-Code:
$a = 1;
$b = 1;
$a = ++$b;
Nach diesen Anweisungen haben sowohl $a
als auch $b
den Wert 2
. Warum? Die
Präfixnotation bedeutet, dass der Wert von $b
inkrementiert wird, bevor er $a
zugewiesen wird. In diesem Ausdruck wird also zuerst $b
auf 2
erhöht und dieser Wert
dann $a
zugewiesen.
Als Postfix sähe das anders aus:
$a = 1;
$b = 1;
$a = $b++;
Auch hier wird $b
inkrementiert und erhält den Wert 2
. Aber der Wert von $a
bleibt 1
.
In der Postfixnotation wird der Wert von $b
nämlich verwendet, bevor er
inkrementiert wird. Perl wertet $b
als 1 aus, weist diesen Wert $a
zu und erhöht erst
dann $b
auf 2
.
Um ganz und gar korrekt zu sein: Meine Reihenfolge, wie die Dinge passieren, ist falsch. Bei einer Variablenzuweisung muss alles auf der rechten Seite des
=
-Operators vor der Zuweisung ausgewertet werden. In Wirklichkeit wird$a
also bis zum allerletzten Schritt gar nicht verändert, sondern Perl merkt sich den ursprünglichen Wert von$b,
inkrementiert ganz brav und greift dann erst bei der Zuweisung an$a
auf den Originalwert von$b
zurück. Aber wenn Sie nicht mit wirklich komplexen Ausdrücken arbeiten, können Sie sich das Ganze auch so vorstellen, dass die Zuweisung vor der Inkrementierung stattfindet.
String- und Textmanagement ist eine von Perls größten Stärken, und etliche der Beispiele in diesem Buch befassen sich mit der Arbeit mit Strings - in Strings suchen, Strings ändern, sie aus Dateien oder von der Tastatur lesen und sie an den Bildschirm, an Dateien oder über ein Netzwerk an einen Webbrowser schicken. Wir haben mit dem Thema erst angefangen und reden noch ganz allgemein über Strings.
Weil es ganz gut in die Lektion von heute paßt, möchte ich hier Perls
Stringoperatoren erwähnen: .
(Punkt) für Stringverkettung und x
für
Stringwiederholung
Anders als Java, das den +
-Operator sowohl für die Addition als auch für die
Stringverkettung nutzt, reserviert Perl +
für die Verwendung mit Zahlen. Um zwei
Strings aneinanderzufügen, verwenden Sie den .
-Operator wie hier:
'es war einmal' . ' vor langer Zeit';
Dieser Ausdruck erstellt einen dritten String: 'es war einmal vor langer Zeit'
. Er
ändert keinen der Originalstrings.
Sie können auch mehrere Strings zu einem einzelnen langen String verketten:
'eene ' . 'meene ' . 'muh... ' . 'und raus bist du!'
Der andere Stringoperator ist der x
-Operator (nicht der X
-Operator, es muss ein
kleines x sein). Der x
-Operator hat einen String auf der einen und eine Zahl auf der
anderen Seite (aber wird beides bei Bedarf konvertieren) und erstellt dann einen neuen
String: Der String links wird so oft wiederholt, wie die Zahl rechts vorgibt. Ein paar
Beispiele:
'blah' x 4; # 'blahblahblahblah'
'*' x 3; # '***'
10 x 5; # '1010101010'
In diesem letzten Beispiel wird die Zahl 10
zum String '10'
konvertiert und dann
fünfmal wiederholt.
Wofür soll das gut sein? Nehmen Sie an, Sie bräuchten für ein Bildschirmlayout eine
bestimmte Zahl von Leerstellen oder Füllzeichen, wobei es aber möglich sein soll, dass
die Breite dieses Layouts variiert. Oder stellen Sie sich vielleicht eine Art ASCII-Kunst
vor, wo die Wiederholung von Buchstaben besondere Muster produziert (das hier ist
Perl, Sie dürfen so eigenartiges Zeug machen, nur zu). Sollten Sie jemals einen String
wiederholen müssen, egal wie oft, kann der x
-Operator das für Sie erledigen.
Der Vorrang (precedence) der Operatoren legt fest, welche Operatoren in einem komplexen Ausdruck zuerst ausgewertet werden. Die Assoziativität bestimmt, wie gleichrangige Operatoren ausgewertet werden (linksassoziative Operatoren von links nach rechts, rechtsassoziative von rechts nach links, und bei nichtassoziativen Operatoren ist die Reihenfolge der Auswertung entweder nicht wichtig, nicht garantiert oder nicht einmal möglich). Tabelle 3.2 zeigt Vorrang und Assoziativität der verschiedenen Perl-Operatoren, wobei Operatoren mit höherem Vorrang (zuerst ausgewertet) in der Tabelle höher stehen als die mit niedrigerem Vorrang (später ausgewertet). Dies ist eine der Tabellen, die Sie bei der Arbeit mit Perl wahrscheinlich immer wieder brauchen werden - ich empfehle Ihnen, diese Seite wie auch immer zu markieren. Auswendig können müssen Sie das alles nicht, aber Sie sollten es schnell parat haben.
Sie können die Auswertungsreihenfolge eines Ausdrucks ändern, indem Sie Klammern setzen. Ausdrücke in Klammern werden vor denen außerhalb der Klammern ausgewertet.
Und noch etwas: In der Tabelle sind auch ein paar Operatoren aufgeführt, die Sie noch nicht kennen (und manche, die ich in diesem Buch nicht einmal behandeln werde). Ich habe bei den Operatoren, die ich später in diesem Buch noch erkläre, Verweise auf die entsprechenden Lektionen eingefügt.
logisches NICHT, bitweises NICHT, Referenz (Tag 19), unäres +, unäres - | ||
Tabelle 3.2: Operatorvorrang und -assoziativität
Und jetzt ein Beispiel namens stats.pl, das Sie um die Eingabe von Zahlen bittet, eine nach der anderen. Wenn Sie mit der Eingabe fertig sind, gibt es aus, wie viele Zahlen es waren, sowie die Summe aller Zahlen und den Durchschnitt. Es ist ein einfaches Statistik-Skript, aber es zeigt Vergleiche und Variablenzuweisungen (und wir werden auf diesem Skript später aufbauen). Hier ein Beispiel, wie es aussieht, wenn es läuft:
% stats.pl
Bitte eine Zahl eingeben: 7
Bitte eine Zahl eingeben: 4
Bitte eine Zahl eingeben: 20
Bitte eine Zahl eingeben: 1
Bitte eine Zahl eingeben: 0.5
Bitte eine Zahl eingeben:
Anzahl der eingegebenen Zahlen: 5
Summe der eingegebenen Zahlen: 32.5
Durchschnitt: 6.50
%
Listing 3.1 zeigt den Code des Statistikskripts.
Wie beim Temperaturumrechnungsbeispiel von gestern gehe ich einfach davon aus, dass Sie nur Zahlen eingeben. Alles andere, aus Versehen oder Absicht, wird zu Perl-Warnungen und möglichen Fehlern führen. Später in dieser Woche lernen Sie mehr über die Eingabeüberprüfung. Im Moment nehmen wir einfach an, wir hätten nur gute Daten zu verarbeiten.
Listing 3.1: Das Skript stats.pl
1: #!/usr/bin/perl -w
2:
3: $input = ''; # Benutzereingaben
4: $count = 0; # Zaehler
5: $sum = 0; # Summe
6: $avg = 0; # Durchschnitt
7:
8: while () {
9: print 'Bitte eine Zahl eingeben: ';
10: chomp ($input = <STDIN>);
11: if ($input ne '') {
12: $count++;
13: $sum += $input;
14: }
15: else { last; }
16: }
17:
18: $avg = $sum / $count;
19:
20: print "\nAnzahl der eingegebenen Zahlen: $count\n";
21: print "Summe der eingegebenen Zahlen: $sum\n";
22: printf("Durchschnitt: %.2f\n", $avg);
Dieses Skript hat drei Hauptabschnitte: einen zum Initialisieren der Variablen, einen zum Einlesen und Speichern der Eingaben und einen zum Berechnen des Durchschnitts und zur Ausgabe der Ergebnisse.
Dies ist der Initialisierungsabschnitt:
3: $input = ''; # Benutzereingaben
4: $count = 0; # Zähler
5: $sum = 0; # Summe
6: $avg = 0; # Durchschnitt
Vier Skalarvariablen werden verwendet: $input
, um die Eingaben zu speichern, wie
sie hereinkommen, $count
, um die Anzahl der eingegebenen Zahlen zu verfolgen
(wegen englisch count, »zählen«, heißen Zählervariablen häufig so). $sum
und $avg
sollen die Summe und den Durchschnitt speichern.
Im nächsten Abschnitt bitten wir um die Eingabe der Daten:
8: while () {
9: print 'Bitte eine Zahl eingeben: ';
10: chomp ($input = <STDIN>);
11: if ($input ne '') {
12: $count++;
13: $sum += $input;
14: }
15: else { last; }
16: }
Dieser Teil des Skripts liest mit einer while
-Schleife und einer if
-Bedingung immer
wieder Eingabedaten ein, und zwar solange, bis wir eine Leerzeile erhalten. Ich werde
Schleifen und Bedingungen erst am Tag 6 behandeln, lassen Sie sich davon also nicht
aufhalten. Vielleicht haben Sie while
s und if
s ja auch schon mal gesehen und
erkennen, dass die while
-Schleife hier keine Abbruchbedingung hat (die Klammern in
Zeile 8 sind leer) und dadurch eine unendliche Schleife ist.
Im Körper der while
-Schleife lesen wir mit Zeile 10 die aktuelle Eingabe ein (und ich
weiß, Sie wollen immer noch wissen, was chomp
und <STDIN>
eigentlich machen, wir
kommen bald dazu). Zeile 11 überprüft, ob die Eingabe etwas enthält. Beachten Sie,
dass es sich hier um einen String-, nicht um einen Zahlenvergleich handelt (ne
).
Wenn Eingabedaten vorhanden sind, inkrementieren wir in Zeile 12 die Variable
$count
und addieren in Zeile 13 den neu eingegebenen Wert zur Variablen $sum
. So
halten wir den Zähler und die Gesamtsumme immer auf dem laufenden. Mit der
Berechnung des Durchschnitts warten wir bis zum Ende der Schleife.
Zeile 15 enthält die else
-Klausel der Bedingung in Zeile 11 - wenn die Eingabe leer
war, dann machen wir direkt hier weiter und steigen mit dem Schlüsselwort last
aus
der unendlichen while
-Schleife aus (Genaueres über last
erfahren Sie, wenn wir uns
am Tag 6 mit Schleifen befassen).
Zu guter Letzt beenden wir alles mit der Berechnung des Durchschnitts und der Ausgabe der Ergebnisse:
18: $avg = $sum / $count;
19:
20: print "\nAnzahl der eingegebenen Zahlen: $count\n";
21: print "Summe der eingegebenen Zahlen: $sum\n";
22: printf("Durchschnitt: %.2f\n", $avg);
Zeile 18 ist einfach die Berechnung des Durchschnitts. Die Zeilen 20 bis 22 geben
den Zähler, die Summe und den Durchschnitt aus. Beachten Sie das \n
am Anfang
der ersten print
-Anweisung; es fügt eine extra Leerzeile vor der Ergebnisausgabe
ein. Sie erinnern sich, dass \n
überall in einem String stehen kann, nicht nur am
Ende.
In der dritten Ergebniszeile verwenden wir wieder printf
zur Formatierung der
Zahlenausgabe. Diesmal haben wir ein printf
-Format genommen, das den Wert als
Fließkommazahl mit 2 Dezimalstellen ausgibt (%.2f
). Im nächsten Abschnitt erfahren
Sie mehr über printf
.
Wir werden den heutigen Tag mit zwei Themen abschließen, die anfangs nicht zu all dem zu passen scheinen, worüber wir bis jetzt im Zusammenhang mit Skalaren gesprochen haben: den Umgang mit Eingabe und Ausgabe, Input und Output. Ich komme hier aus einem wesentlichen Grund dazu: Sie sollen wissen, was in Ihren Skripts abläuft, wenn etwas von der Tastatur gelesen und auf den Bildschirm ausgegeben wird.
In diesem Abschnitt reden wir erst einmal über ganz einfache Eingabe und Ausgabe, im Laufe dieses Buches werden Sie mehr darüber erfahren, insbesondere auch über den Zugriff auf Dateien. Tag 15 schließlich ist ganz diesem Thema gewidmet.
Zuerst etwas Terminologie: In den Skripts von heute und gestern haben Sie mit Ihrem Perl-Code Eingabedaten von der Tastatur eingelesen und Ausgaben an den Bildschirm geschickt. Tastatur und Bildschirm sind aber nicht unbedingt die besten Formulierungen, denn im Grunde genommen lesen Sie von einer Quelle namens Standardeingabegerät (oft auch nur kurz Standard Input oder Standardeingabe genannt) und schreiben zu einem Ziel namens Standardausgabegerät (Standard Output, Standardausgabe). Diese beiden Konzepte sind von Unix-Systemen entliehen. Wenn Sie mit Unix vertraut sind, wird Ihnen die Verwendung von Pipes und Filtern und Redirection geläufig sein. Kennen Sie nur Windows oder Mac, ergibt der Gedanke an ein Standardeingabe- oder -ausgabegerät für Sie wahrscheinlich nicht viel Sinn.
In jedem Fall aber arbeiten Sie, wenn Sie Daten von einer Quelle lesen oder auf ein
Ziel schreiben, mit sogenannten Datei-Handles (File-Handles). Datei-Handles
beziehen sich meist auf Dateien auf einem Speichergerät (Festplatte, Diskette etc.), es
kommt aber auch vor, dass Daten von einer namenlosen Quelle kommen oder dort
hingehen, zum Beispiel von oder zu einem anderen Programm wie einem Webserver.
Zur allgemeinen Handhabung von Datenquellen und -zielen, die keine Dateien sind,
bietet Ihnen Perl vordefinierte Datei-Handles für die Standardeingabe und die
Standardausgabe an: STDIN
und STDOUT
(es gibt auch STDERR
für Standard Error, aber
das heben wir für später auf). Mit diesen beiden Datei-Handles kann man Daten von
der Tastatur holen (STDIN
ist der normale Eingabekanal) und an den Bildschirm
ausgeben (STDOUT
ist der normale Ausgabekanal).
In unseren bisherigen Skripts stand meistens eine Anweisung zum Einlesen der Tastatureingaben, die etwa so aussah:
chomp($eingabezeile = <STDIN>);
So etwas wird Ihnen in Perl-Code häufiger begegnen, auch wenn es oft in mehreren Zeilen steht, etwa so (beide Formen sind äquivalent):
$eingabezeile = <STDIN>
chomp($eingabezeile)
Sie wissen, dass $eingabezeile
eine Skalarvariable ist und dass Sie ihr etwas
zuweisen. Aber was?
Der STDIN
-Teil dieser Zeile ist der vordefinierte Datei-Handle für die Standardeingabe.
Sie brauchen diesen speziellen Datei-Handle weder besonders zu öffnen noch
irgendwie zu organisieren: er steht Ihnen einfach zur Verfügung. Warum er komplett
großgeschrieben ist? Das ist eine Perl-Konvention, damit man Datei-Handles nicht so
leicht mit anderen Sachen durcheinanderbringt (wie zum Beispiel Schlüsselwörtern
der Sprache).
Die spitzen Klammern um STDIN
sind nötig, um Eingaben aus einem Datei-Handle zu
lesen. Die <>
-Zeichen werden auch oft Eingabeoperator genannt (wegen ihrer Form
manchmal auch Diamantoperator). <STDIN>
bedeutet also: »Lies die Eingaben aus
dem Datei-Handle STDIN.
« In diesem besonderen Fall, wo Sie den <STDIN>
-Ausdruck
einer Variablen zuweisen, liest Perl eine Zeile von der Standardeingabe und stoppt,
sobald es zu einem Zeilenvorschub (Newline) oder auf dem Macintosh zu einem
Wagenrücklauf (Carriage Return) kommt. Anders als in C können Sie die Daten nicht
explizit durchlaufen und jedes einzelne Zeichen daraufhin betrachten, ob es ein
Zeilenende ist - Perl erledigt das für Sie. Alles, was Sie brauchen, ist <STDIN>
und eine
Skalarvariable, in der Sie die Eingabezeile dann speichern.
Was für
<STDIN>
eigentlich eine Zeile ist, wird von Perls Input Record Separator festgelegt, dem Trennsymbol für Eingabedatensätze. Voreingestellt ist der Zeilenvorschub. Am Tag 9 erfahren Sie, wie man dieses Trennzeichen ändert. Bis dahin nehmen Sie einfach an, dass das Zeilenendezeichen auch tatsächlich das Ende einer Zeile ist.
Dieses ganze Gerede über Ein- und Ausgabe führt uns endlich auch zu der Funktion
chomp
(vom englischen chomp, »nagen«). Wenn Sie eine Eingabezeile mit <STDIN>
einlesen und in einer Variablen speichern, erhalten Sie alles, was eingetippt wurde,
inklusive dem Zeilenvorschub am Ende. Den wollen Sie normalerweise aber dort gar
nicht haben, es sei denn, Sie geben die Eingabe gleich wieder aus und brauchen ihn
zur Formatierung. Die Perl-Funktion chomp
nimmt einen String, und wenn das letzte
Zeichen ein Zeilenvorschub ist, entfernt es diesen. Beachten Sie, dass chomp
den
Originalstring direkt verändert (anders als Stringverkettung und andere
Stringfunktionen, die komplett neue Strings erstellen und die ursprünglichen Strings
unverändert lassen). Deshalb können Sie chomp
für sich allein in einer eigenen Zeile
aufrufen, ohne der Variablen, die den String enthält, den Wert neu zuweisen zu
müssen:
chomp($eingabezeile)
Frühere Perl-Versionen hatten eine ähnliche Funktion für die gleiche Aufgabe, genannt
chop
. Wenn Sie älteren Perl-Code lesen, werden Sie auf vielchop
stoßen. Der Unterschied zwischenchomp
undchop
ist, dasschop
das letzte Zeichen im String entfernt, ohne zu unterscheiden, ob es ein Zeilenvorschub ist oder nicht.chomp
hingegen ist sicherer: Es schneidet nichts ab außer einen Zeilenvorschub.
Sobald Sie Eingaben in Ihr Perl-Skript geholt haben, von <STDIN>
, aus einer Datei
oder von wo auch immer, können Sie mit diesen Eingaben machen, was Sie wollen.
Irgendwann kommt dabei der Augenblick, wo Sie auch wieder Daten ausgeben
möchten. Die zwei gebräuchlichsten Wege hierfür kennen Sie schon: print
und
printf
.
Fangen wir mit print
an. Die Funktion print
kann beliebig viele Argumente
übernehmen und schickt sie an die Standardausgabe (üblicherweise den Bildschirm).
Bis jetzt haben wir immer nur ein Argument verwendet, aber Sie können auch
mehrere Argumente übergeben, getrennt durch Kommata. Mehrere print
-
Argumente werden verkettet, bevor sie ausgegeben werden:
print 'Guten Morgen!';
print 1, 2, 3; # gibt '123' aus
$a = 4;
print 1, ' ', $a; # gibt "1 4" aus
print 1, " $a"; # gibt auch "1 4" aus
Genaugenommen sind die
Ich habe vorhin schon den Datei-Handle <STDOUT>
als Möglichkeit aufgeführt, das
Standardausgabegerät anzusteuern. Sie haben aber vielleicht bemerkt, dass wir Daten
an den Bildschirm immer nur mit print
ausgegeben haben, ohne uns jemals auf
<STDOUT>
beziehen zu müssen. Perl will Ihnen Zeit und Tipparbeit ersparen und geht
deswegen davon aus, dass Sie die Standardausgabe benutzen wollen, wenn Sie print
ohne einen expliziten Datei-Handle verwenden. Die beiden folgenden Anweisungen
bewirken exakt das gleiche:
print "Hallo Welt!\n" ;
print STDOUT "Hallo Welt!\n";
Am Tag 15, wenn wir über Datei-Handles sprechen, die mit echten Dateien
verbunden sind, erfahren Sie mehr über die lange Version von print
.
Zusätzlich zum alten Arbeitspferd print
bietet Perl auch die Funktionen printf
und
sprintf
. Diese beiden Funktionen sind äußerst nützlich für spezielle Formatierungen
und Ausgaben von Zahlen. Sie arbeiten fast genauso wie die gleichnamigen
Funktionen in C, aber seien Sie vorsichtig: printf
ist bei weitem nicht so effizient wie
print
. Nehmen Sie also nicht einfach an, Sie können printf
überall verwenden, weil
Sie es so gewohnt sind. Verwenden Sie printf
nur, wenn Sie dafür einen besonderen
Grund haben.
Wie Sie seit gestern wissen, verwendet man die printf
-Funktion, um formatierte
Zahlen und Strings auszugeben, zum Beispiel an die Standardausgabe. sprintf
formatiert einen String und gibt dann einfach nur den neuen String zurück, ist also
geeigneter für Verschachtelungen innerhalb von Ausdrücken (tatsächlich ruft sogar
printf
für die Formatierungsarbeit sprintf
auf).
An beide Funktionen, printf
und sprintf
, übergibt man zwei oder mehr Argumente:
Das erste Argument ist ein String mit Formatierungscodes, das zweite und alle
weiteren sind die Werte, auf die diese Codes angewendet werden sollen. Wir hatten
vorhin ein Beispiel von printf
, das eine Fließkommazahl auf zwei Dezimalstellen
abgeschnitten hat:
printf("Durchschnitt: %.2f", $avg);
Wir haben auch schon gesehen, wie man auf den nächsten ganzzahligen Wert abrundet:
printf("%d Grad Celsius\n", $cel);
Gestern haben Sie zudem gesehen, wie man mit sprintf
eine Fließkommazahl auf
zwei Nachkommastellen beschränkt:
$wert = sprintf("%.2f", $wert);
Die Formatierungscodes folgen denselben Regeln wie die C-Versionen (obwohl der
Längenspezifikator *
nicht unterstützt wird) und können recht komplex werden. Ein
simpler Formatierungscode, den Sie in Perl verwenden könnten, hat folgende Syntax:
%l.px
Wobei x
für einen Code steht, der auf den Wertetyp verweist. Am interessantesten
sind für Sie wahrscheinlich der Formatierungscode d
zur Ausgabe von Integern
(ganzzahligen Werten) und der Code f
für die Ausgabe von Fließkommazahlen. Das l
und das p
im Formatierungscode sind beide optional. l
bezieht sich auf die Anzahl der
Zeichen, die der Wert im Ergebnisstring aufnehmen soll (aufgefüllt mit Leerzeichen,
wenn der Wert des Ausdrucks weniger als l
Stelle hat), und p
auf die Anzahl der
Nachkommastellen in einer Fließkommazahl. Alle Zahlen werden auf das
entsprechende Format gebracht.
Hier einige typische Beispiele, wie sprintf
oder printf
eingesetzt werden könnte:
$wert = 5.4349434;
printf("->%5d\n", $wert); # -> 5
printf("->%11.5f\n", $wert); # -> 5.43494
printf("%d\n", $wert); # 5
printf("%.3f\n", $wert); # 5.435
printf("%.1f\n", $wert); # 5.4
Stehen mehrere Formatierungscodes hintereinander, werden sie von links nach rechts ausgewertet, wobei jeder Formatierungscode durch ein Argument ersetzt wird (daher sollten Sie gleichviel Formatierungscodes wie Extraargumente haben):
printf("Startwert: %.2f Endwert: %.2f\n", $start, $end);
Wenn in diesem Beispiel $start
gleich 1.343
und $end
gleich 5.33333
ist, wird die
Anweisung folgendes ausgeben:
Startwert: 1.34 Endwert: 5.33
Wenn Sie mit den printf
-Formatierungscodes aus C nicht vertraut sind, finden Sie
mehr darüber in der perlfunc
-Manpage (oder der printf-Manpage).
Jetzt, da Sie die Funktionen print
und chomp
kennengelernt und einen kleinen Blick
auf andere Funktionen wie oct
und int
und sprintf
geworfen haben, ist ein guter
Zeitpunkt, zu erklären, wie Funktionsaufrufe funktionieren. Wenn Sie genau
aufgepaßt haben, haben Sie vielleicht bemerkt, dass ich die print
-Funktion
folgendermaßen aufrufe:
print "Hallo, Welt!\n";
Ich habe aber chomp
und printf
folgendermaßen aufgerufen:
chomp($input = <STDIN>);
printf("Durchschnitt: %.2f", $avg);
Einmal stehen die Funktionsargumente in Klammern, das andere Mal nicht. Was ist nun richtig? Die Antwort ist: beides. Klammern um die Funktionsargumente sind optional - solange Perl versteht, was Ihre Argumente sind, kommt es mit beiden Formen wunderbar zurecht.
Ich verwende in diesem Buch beide Varianten. Meine generelle Regel ist, dass ich
keine Klammern setze, wenn eine Funktion ein einziges Argument entgegennimmt -
int
oder oct
sind hierfür gute Beispiele. Wenn mehrere Argumente übergeben
werden oder das Argument ein Ausdruck ist (wie häufig bei printf
oder chomp
der
Fall), setze ich Klammern.
Je nachdem, womit Sie sich vertraut fühlen - und was Ihnen richtiger scheint - schaffen Sie sich ruhig Ihre eigene Regel für das Einklammern von Funktionsargumenten. Ich sollte allerdings erwähnen, dass die Regel »Klammern sind optional, solange Perl versteht, was Ihre Argumente sind« gelegentlich schwierig zu begreifen ist, besonders bei mehreren Argumenten und noch mehr, wenn einige davon eingeklammerte Ausdrücke oder Listen sind. Und als wäre das noch nicht komplex genug: Einige von Perls eingebauten Funktionen sind eigentlich gar keine Funktionen, sondern Operatoren und haben deswegen einen anderen Vorrang als echte Funktionsaufrufe (mehr darüber im nachfolgenden Vertiefungsabschnitt). Es gibt genaue Rangfolgeregeln, wie komplexe Funktionsaufrufe ausgewertet werden. Doch die einfachste und sicherste Lösung, wenn Perl Ihre Argumente zu ignorieren scheint oder unerwartete Ergebnisse produziert, sind Klammern um alle Argumente. Die Aktivierung von Perl-Warnungen kann ebenfalls beim Abfangen einiger dieser Probleme hilfreich sein.
Noch nicht genug von Strings und Zahlen? Sie wollen mehr? Kein Problem. Dieser Abschnitt behandelt ein paar andere bemerkenswerte Eigenheiten im Zusammenhang mit skalaren Daten, bevor wir mit Listen weitermachen.
Alle Operatoren werden in der perlop-Manpage besprochen, die Funktionen in der
perlfunc-Manpage. Wie ich bereits erwähnt habe: Sie kommen zu all diesen Seiten
mit dem Befehl perldoc
oder über die Website http://www.perl.com/CPAN-local/doc/
manual/html/pod
.
Perl enthält eine recht kleine Anzahl an Funktionen für eine Vielzahl von Zwecken. Diese Funktionen sind in Anhang A zusammengefaßt; die perlfunc-Manpage beschreibt sie noch detaillierter. Insbesondere bietet Perl nützliche Funktionen für Zahlen und Strings, inklusive der in Tabelle 3.3 aufgelisteten. Wir werden einige davon in den folgenden Kapiteln noch genauer untersuchen, andere können Sie selbst erforschen.
Tabelle 3.3: Zahlen- und String-Funktionen
Perl bietet den üblichen Satz C-ähnlicher Operatoren zum Spielen mit Bits in Integer-
Zahlen: ~
, <<
, >>
, &
. | und ^. Auch für diese Operatoren gibt es
Zuweisungsabkürzungen. Genaueres finden Sie in der perlop-Manpage.
Zusätzlich zu den Vergleichsoperatoren, die ich im Abschnitt über Vergleiche
beschrieben haben, verfügt Perl noch über die Operatoren <=>
und cmp
. Ersterer ist
für Zahlen, der zweite für Strings. Beide geben -1
, 0
oder 1
zurück, je nachdem, ob
der linke Operator größer ist als der rechte, die Operatoren gleich sind oder der
rechte Operator größer ist als der linke. Diese Operatoren verwendet man meistens
zum Sortieren, worüber Sie am Tag 8 mehr erfahren werden.
Die in Perl eingebauten Funktionen bestehen aus zwei Gruppen: Funktionen und Operatoren, an die ein Argument übergeben wird und die nur wie Funktionen aussehen. Die funktionsähnlichen Operatoren stehen in der Mitte der Auswertungsrangfolge und verhalten sich in dieser Hinsicht wie Operatoren (während Funktionsaufrufe mit Klammern immer den höchsten Vorrang haben). Sehen Sie in der perlop-Manpage unter »Named Unary Operators« nach der Liste dieser Funktionen.
Heute haben wir uns weiter durch die skalaren Daten gearbeitet. Sie haben weitere Operatortabellen gesehen und die Operatoren für die Zuweisung an Variablen, zur Änderung der Werte von Variablen und für die Verkettung und Wiederholung von Strings kennengelernt. Sie haben auch etwas über die Rangfolge von Operatoren gelernt, die bestimmt, welcher Operator zuerst abgearbeitet wird, wenn Sie mehrere Operatoren in einem Ausdruck stehen haben.
Am Ende der heutigen Lektion haben wir die Ein- und Ausgabe behandelt,
insbesondere die Verwendung von <STDIN>
, um Daten in ein Perl-Skript
hineinzubekommen, und die verschiedenen print-Funktionen, um sie wieder
auszugeben. Und Sie haben bereits etwas über den Aufruf von Funktionen mit und
ohne Klammern um die Argumente erfahren.
Folgende Perl-Funktionen wurden heute besprochen:
print
nimmt eine Liste von kommagetrennten Werten und Strings entgegen und
gibt diese Werte an das Standardausgabegerät <STDOUT>
aus.
printf
nimmt einen Formatierungsstring und beliebig viele Werte entgegen und
gibt diese Werte entsprechend den Formatierungsanweisungen aus.
sprintf
macht dasselbe wie printf
, außer dass es den formatierten String
zurückgibt, ohne irgend etwas auszugeben.
chomp
mit einem String-Argument schneidet alle Zeilenvorschubzeichen von
diesem String ab und gibt die Anzahl der entfernten Zeichen zurück.
chop
ist die ältere Version von chomp
; es entfernt das letzte Zeichen vom String
und gibt das gelöschte Zeichen zurück.
Schlagen Sie in der perlfunc-Manpage (siehe auch Anhang A) nach, um mehr über diese Funktionen zu erfahren.
Frage:
Ich möchte einen String Buchstabe für Buchstabe durchgehen und zählen, wie oft
der Buchstabe »t« vorkommt. Wie kann ich das in Perl bewerkstelligen?
Antwort:
Nun ja, Sie könnten sich mit einer for
-Schleife und einer Stringfunktion
Buchstabe für Buchstabe durch den String arbeiten, aber das wäre wohl ein
ziemlicher Overkill (und würde Sie als C-Programmierer outen, der bei Strings
noch an nullterminierte Arrays denkt). Strings sind eine der besonderen
Stärken von Perl, das über eingebaute Mechanismen zur Suche in Strings
verfügt. Darum brauchen Sie diese entsetzlichen Buchstabe-für-Buchstabe-
Vergleiche gar nicht. Am Tag 9 werden Sie mehr über diese
Suchmechanismen, das sogenannte Pattern Matching, lernen. Bis dahin
verschwenden Sie nicht soviel Zeit mit dem Iterieren über Strings - es geht
wirklich viel einfacher.
Frage:
Kann ich printf
genauso verwenden wie in C?
Antwort:
Ja, das können Sie, aber Sie sollten sich wirklich angewöhnen, statt dessen
mit print
zu arbeiten. Die print
-Funktion ist effizienter und hilft beim
Ausgleichen von Abrundungsfehlern in Fließkommazahlen. Es ist (ganz
ehrlich) in den allermeisten Fällen die bessere Idee, print
zu verwenden und
auf printf
nur in bestimmten Fällen (beispielsweise zum Runden)
zurückzukommen. Mit printf
können Sie alle Formatierungsanweisungen
aus der Sprache C verwenden, außer *
.
Frage:
Warum ist es wichtig, dass manche Funktionen Funktionen und manche eigentlich
Operatoren sind? Benehmen sich nicht alle gleich?
Antwort:
Nein. Funktionen und Operatoren verhalten sich leicht unterschiedlich.
Funktionen haben zum Beispiel einen höheren Rang. Außerdem können
Argumente an einen Operator auf Vorrangsbasis gruppiert werden (was zu
unerwarteten Ergebnissen führen kann). In den meisten Fällen aber sollte der
Unterschied zwischen einer Funktion und einem Operator Ihnen nicht den
Schlaf rauben.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.
$x++
) und dem
Präfix-Inkrementoperator (++$x
)?
chomp
?
print
, printf
und sprintf
? Wann
verwenden Sie welche Funktion?
.
**
ne
||
*=
while () {
print 'Einen Namen eingeben: ';
chomp ($input = <INPUT>);
if ($input ne '') {
$namen++;
}
else { last; }}
length
liefert Ihnen die
Länge eines Strings in Zeichen.
Hier die Antworten auf die Workshop-Fragen aus dem vorigen Abschnitt.
chomp
entfernt das Zeilenvorschubzeichen vom Ende eines Strings.
Wenn dort kein Zeilenvorschub steht, macht chomp
gar nichts.
print
-Funktion ist der übliche Weg, etwas auf den Bildschirm oder andere
Ziele auszugeben. Die Funktion printf
gibt formatierte Strings auf bestimmte
Ziele aus; sprintf
formatiert einen String und liefert diesen formatierten String
als Wert zurück anstatt ihn auszugeben.
.
verkettet Strings
**
erzeugt Exponentialzahlen
ne
»ungleich« für Strings
||
logisches ODER (C-Stil)
*=
Multiplizieren und Zuweisen, dasselbe wie $x = $x * $y
#!/usr/bin/perl -w
$input = ''; # Eingabe
$zeilen = 0; # Zeilenzaehler
while () {
print 'Geben Sie etwas Text ein: ';
chomp ($input = <STDIN>);
if ($input ne '') {
$zeilen++;
}
else { last; }
}
print "Zahl der eingegebenen Zeilen: $zeilen\n";
STDIN
, nicht INPUT
.
#!/usr/bin/perl -w
$input = ''; # Benutzereingaben
$satz = ''; # Ergebnis-Satz;
while () {
print 'Geben Sie ein Wort ein: ';
chomp ($input = <STDIN>);
if ($input ne '') {
$satz .= $input . ' ';
}
else { last; }
}
print "ergibt den Satz: $satz\n";
#!/usr/bin/perl -w
$input = ""; # Benutzereingaben
$leer = 0; # Leerstellen drum herum
$laenge = 0 ; # Länge des Strings
print 'Geben Sie etwas Text ein: ';
chomp ($input = <STDIN>);
$laenge = length $input;
$leer = int((80 - $laenge) / 2);
print ' ' x $leer;
print $input;
print ' ' x $leer . "\n";
print '*' x 80;